﻿using System;
using System.Windows;
using theeg.GraphWpf.Models;

namespace theeg.GraphWpf.Arrangement
{
    internal static class BusRouting
    {
        private const double Margin = 20.0;

        private static void CalculateEndpointOrientation(Transition transition, RoutingConfiguration configuration)
        {
            transition.RoutingPoints.Clear();

            var source = transition.Source;
            var target = transition.Target;
            transition.SourceOrientation = configuration.ConnectorDefault;

            double temp = configuration.GetOffset(source) + configuration.GetExtent(source) + Margin;
            if (temp < configuration.GetOffset(target))
            {
                transition.TargetOrientation = configuration.ConnectorAlternate;
            }
            else
            {
                if (configuration.GetSecondDimensionOffset(source) + configuration.GetSecondDimensionExtent(source) * 0.5
                    > configuration.GetSecondDimensionOffset(target) + configuration.GetSecondDimensionExtent(target) * 0.5)
                {
                    //route to before
                    transition.TargetOrientation = configuration.GetSecondDimensionOffset(target) + configuration.GetSecondDimensionExtent(target) + Margin
                                                   > configuration.GetSecondDimensionOffset(source) - Margin
                                                   ? configuration.ConnectorSecondDimensionDefault
                                                   : configuration.ConnectorSecondDimensionAlternate;
                }
                else
                {
                    //route to after
                    transition.TargetOrientation = configuration.GetSecondDimensionOffset(target) - Margin
                                                   > configuration.GetSecondDimensionOffset(source) + configuration.GetSecondDimensionExtent(source) + Margin
                                                   ? configuration.ConnectorSecondDimensionDefault
                                                   : configuration.ConnectorSecondDimensionAlternate;
                }
            }
            transition.RoutingPoints.Add(RoutingMediator.OrientationToEndpoint(transition.SourceOrientation, transition.Source));
            transition.RoutingPoints.Add(RoutingMediator.OrientationToEndpoint(transition.TargetOrientation, transition.Target));

        }

        public static void CalculateRoutingPoints(Transition transition, RoutingConfiguration configuration)
        {
            transition.RoutingPoints.Clear();
            CalculateEndpointOrientation(transition, configuration);

            var source = transition.Source;
            var target = transition.Target;
            Point p1 = transition.RoutingPoints[0];
            Point p2 = transition.RoutingPoints[1];
            int index = 1;

            var sourceOffset1 = configuration.GetOffset(source);
            var sourceExtent1 = configuration.GetExtent(source);
            double temp = sourceOffset1 + sourceExtent1 + Margin;

            var targetOffset2 = configuration.GetSecondDimensionOffset(target);
            var sourceOffset2 = configuration.GetSecondDimensionOffset(source);
            var targetExtent2 = configuration.GetSecondDimensionExtent(target);
            var sourceExtent2 = configuration.GetSecondDimensionExtent(source);
            if (sourceOffset1 + sourceExtent1 < configuration.GetOffset(target)
                && Equals(sourceOffset2 + sourceExtent2*0.5, targetOffset2 + targetExtent2*0.5)) return;

            transition.RoutingPoints.Insert(index++, configuration.CreateIntermediatePoint(temp, p1));
            if (Equals(temp, configuration.GetOffset(target)))
            {
                //one point
            }
            else if (temp < configuration.GetOffset(target))
            {
                //child is below parent -> two points
                transition.RoutingPoints.Insert(index, configuration.CreateIntermediatePoint(temp, p2));
            }
            else
            {
                double tempSecond;
                //three points
                if (sourceOffset2 + sourceExtent2 * 0.5 > targetOffset2 + targetExtent2 * 0.5)
                {
                    //route to left
                    if (targetOffset2 + targetExtent2 + Margin > sourceOffset2 - Margin)
                    {
                        tempSecond = Math.Min(targetOffset2, sourceOffset2) - Margin;
                    }
                    else
                    {
                        tempSecond = sourceOffset2 - Margin;
                    }
                }
                else
                {
                    //route to right
                    if (targetOffset2 - Margin > sourceOffset2 + sourceExtent2 + Margin)
                    {
                        tempSecond = sourceOffset2 + sourceExtent2 + Margin;
                    }
                    else
                    {
                        tempSecond = Math.Max(targetOffset2 + targetExtent2, sourceOffset2 + sourceExtent2) + Margin;
                    }
                }
                transition.RoutingPoints.Insert(index++, configuration.CreateIntermediatePoint3(temp, tempSecond));
                transition.RoutingPoints.Insert(index, configuration.CreateIntermediatePoint2(p2, tempSecond));
            }
        }
    }
}
